package edu.zhuravlev;


import edu.zhuravlev.exception.TrainingParseException;
import edu.zhuravlev.model.Exercise;
import edu.zhuravlev.model.TrainingResults;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TrainingMessageParser {

    private static final Pattern WEIGHT_PATTERN = Pattern.compile("^\\((\\d+\\.?\\d+|\\d+)кг\\)$");

    private static final Pattern REPEATS_PATTERN = Pattern.compile("(^\\d+$)|(^\\d+(,\\s*\\d+)*$)");

    public TrainingResults parse(String data) throws TrainingParseException {
        if (data == null || data.isEmpty()) {
            throw new TrainingParseException("В парсер передана пустая информация");
        }

        Scanner scanner = new Scanner(data);
        List<Exercise> exercises = new ArrayList<>();

        Exercise exercise;

        while (scanner.hasNext()) {
            String row = scanner.nextLine();

            if (row.isEmpty() || row.isBlank()) {
                continue;
            }

            exercise = parseRow(row);
            exercises.add(exercise);
        }

        return new TrainingResults(exercises);
    }

    private Exercise parseRow(String row) throws TrainingParseException {
        Exercise.ExerciseBuilder builder = Exercise.builder();
        String[] partitions = row.split(":");

        if (partitions.length < 3 || partitions.length % 2 == 0) {
            throw new TrainingParseException("Передана строка неправильного формата: [%s]".formatted(row));
        }

        String name = partitions[0];
        name = name.trim().toLowerCase();

        if (name.isEmpty()) {
            throw new TrainingParseException("Название упражнения не может быть пустым. Ошибка в строке: [%s]".formatted(row));
        }

        builder.exerciseName(name);

        Map<Double, List<Integer>> weightAndRepeats = new HashMap<>();

        for (int i = 1; i < partitions.length; i += 2) {
            Map.Entry<Double, List<Integer>> pair = parseWeightAndRepeatsPair(partitions[i], partitions[i + 1]);
            weightAndRepeats.put(pair.getKey(), pair.getValue());
        }

        builder.weightAndRepeats(weightAndRepeats);
        return builder.build();
    }

    private Map.Entry<Double, List<Integer>> parseWeightAndRepeatsPair(String weight, String repeats) throws TrainingParseException {
        weight = weight.trim().toLowerCase();
        repeats = repeats.trim();

        Matcher weightMatcher = WEIGHT_PATTERN.matcher(weight);

        if (!weightMatcher.matches()) {
            throw new TrainingParseException("Указанный вес не соответствует шаблону: [%s]".formatted(weight));
        }

        Double numberWeight = Double.parseDouble(weightMatcher.group(1));

        Matcher repeatsMatcher = REPEATS_PATTERN.matcher(repeats);

        if (!repeatsMatcher.matches()) {
            throw new TrainingParseException("Число повторений не соответствует шаблону: [%s]".formatted(repeats));
        }

        String[] repeatsParts = repeats.split(",");
        List<Integer> listRepeats = new ArrayList<>(repeatsParts.length);

        for (String repeat : repeatsParts) {
            listRepeats.add(Integer.parseInt(repeat.trim()));
        }

        return new AbstractMap.SimpleEntry<>(numberWeight, listRepeats);
    }
}
